package com.atguigu.tingshu.payment.service.impl;


import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private RSAAutoCertificateConfig config;


    @Override
    public Map<String, String> createJsapi(String paymentType, String orderNo) {
        //1.保存本地交易记录
        PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo);
        if (SystemConstant.PAYMENT_STATUS_UNPAID.equals(paymentInfo.getEpaymentStatus())) {
            throw new GuiguException(500, "订单未取消");
        }
        log.info("开始调用微信支付接口");
        //2.对接微信支付获取小程序拉起微信支付所需参数
        //2.1 创建JSAPI 支付业务对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        //2.2 设置所需参数：填充预下单参数
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        //TODO 测试阶段 设置为1分
        amount.setTotal(1);
        request.setAmount(amount);
        //TODO 测试阶段小程序未上线 需要设置付款者微信账户的openId 需要应用下开发者用户
        Payer payer = new Payer();
        payer.setOpenid("odo3j4qp-wC3HVq9Z_D9C0cOr0Zs");
        request.setPayer(payer);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setDescription(paymentInfo.getContent());
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        request.setOutTradeNo(paymentInfo.getOrderNo());
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);

        if (response != null) {
            String timeStamp = response.getTimeStamp();
            String nonceStr = response.getNonceStr();
            String packageVal = response.getPackageVal();
            String signType = response.getSignType();
            String paySign = response.getPaySign();
            Map<String, String> map = new HashMap<>();
            map.put("timeStamp", timeStamp);
            map.put("nonceStr", nonceStr);
            map.put("package", packageVal);
            map.put("signType", signType);
            map.put("paySign", paySign);
            return map;
        }
        return null;
    }

    @Override
    public Boolean queryPayStatus(String orderNo) {
/*        //1.创建JSAPI 支付业务对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        //2.调用根据商户侧订单号查询支付结果
        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setOutTradeNo(orderNo);
        Transaction transaction = service.queryOrderByOutTradeNo(request);
        //3.1 解析交易对象结果
        if (transaction != null) {
            log.info("查询订单：{}，支付结果：{}", orderNo, transaction);
            Transaction.TradeStateEnum tradeState = transaction.getTradeState();
            if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
                //说明用户付款成功 进一步判断付款金额
                Integer payerTotal = transaction.getAmount().getPayerTotal();
                if (payerTotal.intValue() == 1) {
                    return true;
                }
            }
        }
        return false;*/

        //1.1 伪造创建微信交易结果对象
        //1.1 伪造创建微信交易结果对象
        Transaction transaction = new Transaction();
        //微信支付交易编号
        transaction.setTransactionId("wx" + IdUtil.getSnowflakeNextId());
        //商户侧订单编号
        transaction.setOutTradeNo(orderNo);
        //2.调用本地交易记录业务层处理支付成功后核心业务
        paymentInfoService.updatePaymentInfo(transaction);

        return true;
    }

    /**
     * 微信支付成功异步回调
     *
     * @param request
     * @return
     */

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Map<String, String> paymentSuccessNotify(HttpServletRequest request) {
        //1.解析微信异步回调的方法
        //1.验证签名，防止出现虚假通知，造成商户损失
        //1.1 从请求头中获取封装请求参数对象数据
/*        String signature = request.getHeader("Wechatpay-Signature");
        String serial = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String signaureType = request.getHeader("Wechatpay-Signature-Type");
        log.info("签名：{}，序列号：{}，随机数：{}，时间戳：{}，签名类型：{}", signature, serial, nonce, timestamp, signaureType);
        //1.2 获取请求体数据（此时加密数据）
        String body = PayUtil.readData(request);
        //2.参数解密：获取支付结果相关数据
        //2.1 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder().serialNumber(serial).nonce(nonce).signature(signature).timestamp(timestamp).body(body).build();
        //2.2 初始化NotificationParser通知解析器对象用于参数解密
        NotificationParser parser = new NotificationParser(config);
        //2.3 完成验签解密请求体参数
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if (transaction != null) {
            //3 保存本地记录并且进行幂等性得处理
            String transactionId = transaction.getTransactionId();
            String key = "payment:info" + transactionId;
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "", 25, TimeUnit.HOURS);
            if (flag) {
                try {
                    if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
                        paymentInfoService.updatePaymentInfo(transaction);
                        return Map.of("code", "SUCCESS", "message", "成功");
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }*/
        return null;
    }
}
